import pyautogui
import time
import os
import pyperclip
import logging
from pynput import mouse, keyboard
from pynput.keyboard import Key, KeyCode
# '''类定义'''
class AutomationTool:
    OPERATION_DESCRIPTION = '''
    | 操作名称         | 函数                       | 需要的参数                          | 参数说明                         | 返回参数                     |
    | --------------- | -------------------------- | ---------------------------------- | ------------------------------ | -------------------------- |
    | 延时等待         | sleep                      | s                                  | 等待时间(秒)                    | bool：操作是否成功          |
    | 按位置点击左键       | click_at_position          | x, y                              | 分开的x和y坐标（整数类型）                     | bool：点击是否成功          |
    | 按位置点击右键       | click_at_position_right    | x, y                              | 分开的x和y坐标（整数类型）                     | bool：点击是否成功          |
    | 鼠标移动到指定位置   | move_to_position           | x, y                              | 分开的x和y坐标（整数类型）                     | bool：移动是否成功          |
    | 按住鼠标按键N秒后松开 | press_mouse_button         | button, seconds=1                 | button：鼠标按键（'left'、'right'或'middle'）；seconds：按住时间（秒） | bool：操作是否成功          |
    | 按住键盘按键N秒后松开 | press_key                  | key, seconds=1                    | key：键盘按键名称；seconds：按住时间（秒）       | bool：操作是否成功          |
    | 文本粘贴         | input_text                 | text                               | 要输入的文本内容                | bool：粘贴是否成功          |
    | 图片识别         | image_recognition          | image_path                        | 图片文件路径                    | (bool, location)：是否识别到及位置 |
    | 图片识别后点击   | click_on_image             | image_path                        | 要识别并点击的图片路径           | bool：点击是否成功          |
    | 模拟组合按键     | hotkey                     | key1, key2                        | 组合键名称(如'ctrl','c')        | bool：按键是否成功          |
    | 模拟单按键       | press                      | key                               | 按键名称(如'enter')             | bool：按键是否成功          |
    | 鼠标滚动         | scroll                     | amount                            | 滚动距离(正数向上，负数向下)    | bool：滚动是否成功          |
    | 鼠标拖拽         | drag                       | start_xy, end_xy, duration=0.5    | 起始坐标(start_x,start_y)，结束坐标(end_x,end_y)，持续时间(秒) | bool：拖拽是否成功          |
    | 截图            | capture_screen             | output_path, region=None          | 保存路径，可选区域(left,top,width,height) | bool：操作是否成功          |
    | 获取鼠标位置     | get_mouse_position         | 无需参数                          | 按下F8热键后获取当前鼠标位置     | (x, y)：鼠标当前位置坐标 |
    | 记录日志         | log                        | content                           | 要记录的日志内容                 | bool：操作是否成功          |
    '''
    # 初始化
    def __init__(self, logger=None):
        self.pyautogui = pyautogui
        self.pyautogui.PAUSE = 0
        self.pyperclip = pyperclip
        self.time = time
        self.mouse = mouse
        self.keyboard = keyboard
        
        # 使用外部传入的 logger，否则创建默认 logger
        if logger is not None:
            self.logger = logger
        else:
            # 默认 logger（仅用于独立测试，前端场景会被覆盖）
            self.logger = logging.getLogger('AutomationTool')
            self.logger.setLevel(logging.INFO)
        
        # 录制状态
        self.is_recording = False
        self.mouse_listener = None
        self.keyboard_listener = None
    # 录制——键盘
    def log_keyboard_press(self, key):
        """记录键盘按键事件（按下时触发）"""
        key_name = self._parse_key_name(key)
        self.logger.info(f"按下[{key_name}],keycode(ASCII控制码)为{key}")

    def _parse_key_name(self, key):
        """解析键盘按键名称"""
        try:
            # 处理普通字符键（如a/A/1等）
            return key.char
        except AttributeError:
            # 处理特殊功能键（映射为中文描述）
            key_mapping = {
                keyboard.Key.shift: "Shift",
                keyboard.Key.shift_l: "Shift",   # 左Shift
                keyboard.Key.shift_r: "Shift",   # 右Shift
                keyboard.Key.ctrl: "Ctrl",         # 通用Ctrl（部分系统可能默认右Ctrl）
                keyboard.Key.ctrl_l: "Ctrl",     # 显式映射左Ctrl
                keyboard.Key.ctrl_r: "Ctrl",     # 显式映射右Ctrl
                keyboard.Key.alt: "Alt",
                keyboard.Key.alt_l: "Alt",       # 左Alt
                keyboard.Key.alt_r: "Alt",       # 右Alt
                keyboard.Key.enter: "Enter",
                keyboard.Key.tab: "Tab",
                keyboard.Key.backspace: "Backspace",
                keyboard.Key.esc: "Esc",
                keyboard.Key.up: "上箭头",
                keyboard.Key.down: "下箭头",
                keyboard.Key.left: "左箭头",
                keyboard.Key.right: "右箭头",
                keyboard.Key.space: "空格",
                keyboard.Key.caps_lock: "大写锁定",
                keyboard.Key.num_lock: "数字锁定",
                keyboard.Key.scroll_lock: "滚动锁定",
                keyboard.Key.delete: "Delete",
                keyboard.Key.home: "Home",
                keyboard.Key.end: "End",
                keyboard.Key.f1: "F1",
                keyboard.Key.f2: "F2",
                keyboard.Key.f3: "F3",
                keyboard.Key.f4: "F4",
                keyboard.Key.f5: "F5",
                keyboard.Key.f6: "F6",
                keyboard.Key.f7: "F7",
                keyboard.Key.f8: "F8",
                keyboard.Key.f9: "F9",
                keyboard.Key.f10: "F10",
                keyboard.Key.f11: "F11",
                keyboard.Key.f12: "F12",
                keyboard.Key.insert: "Insert",
                keyboard.Key.page_up: "PageUp",
                keyboard.Key.page_down: "PageDown",
                # 可根据需要扩展更多特殊键映射（如多媒体键等）
            }
            return key_mapping.get(key, f"未知键({repr(key)})")  # 未识别的键显示原始标识
    
    # 录制——鼠标
    def log_mouse_click(self, x, y, button, pressed):
        if pressed:
            self.logger.info(f"点击({x},{y}) {'左键' if button == mouse.Button.left else '右键'}")
    # 录制——开始
    def start_recording(self):
        """开始录制 - 核心功能"""
        self.is_recording = True
        self.recorded_actions = []
        # 绑定鼠标点击监听器
        self.mouse_listener = mouse.Listener(on_click=self.log_mouse_click)
        # 绑定键盘监听器
        self.keyboard_listener = keyboard.Listener(on_press=self.log_keyboard_press)
        self.mouse_listener.start()
        self.keyboard_listener.start()
        self.logger.info("录制已开始")
    # 录制——结束
    def stop_recording(self):
        """停止录制 - 核心功能"""
        if self.mouse_listener:
            self.mouse_listener.stop()
        if self.keyboard_listener:
            self.keyboard_listener.stop()
        self.is_recording = False
        self.logger.info("录制已停止")
        self.logger.info('''
        你是一个操作日志分析专家，请严格按以下规则解析用户提供的倒序操作日志：
        1. **时间正序处理**：按时间排序，忽略无关日志
        2. **操作精简规则**：
           - 连续字母键+空格 → 用拼音输入法合并为「输入文本：[推测内容]」
           - Ctrl/Alt等特殊键后跟着一个单键 → 合并为「快捷键：[组合名称]」
           - 坐标点击 → 简化为「点击(x,y)」
        3. **输出格式**：
           [步骤序号]. [操作类型] 
           （最后请求用户确认）
        4. **智能推测**：
           • 拼音输入需推测合理中文
           • 连续操作暗示流程关联性，如连续点击、输入文字等
        ''')
        return self.recorded_actions.copy()

    # 按位置点击左键，参数为x,y坐标，返回值为bool
    def click_at_position(self, x, y):
        # 直接接收分开的x和y坐标参数
        try:
            # 确保x和y为整数类型
            x = int(x)
            y = int(y)
            self.pyautogui.click(x, y)
            self.logger.info(f"点击坐标({x},{y})成功")
            return True
        except Exception as e:
            self.logger.error(f"点击坐标失败: {str(e)}")
            return False
    
    # 按位置点击右键，参数为x,y坐标，返回值为bool
    def click_at_position_right(self, x, y):
        # 直接接收分开的x和y坐标参数
        try:
            # 确保x和y为整数类型
            x = int(x)
            y = int(y)
            self.pyautogui.click(x, y, button='right')
            self.logger.info(f"点击坐标({x},{y})成功")
            return True
        except Exception as e:
            self.logger.error(f"点击坐标失败: {str(e)}")
            return False

    # 鼠标移动到指定位置，参数为x,y坐标，返回值为bool
    def move_to_position(self, x, y):
        # 直接接收分开的x和y坐标参数
        try:
            # 确保x和y为整数类型
            x = int(x)
            y = int(y)
            self.pyautogui.moveTo(x, y)
            self.logger.info(f"移动到坐标({x},{y})成功")
            return True
        except Exception as e:
            self.logger.error(f"移动到坐标失败: {str(e)}")
            return False

    # 按住鼠标N秒再松开，参数为鼠标左键、右键、中键和时间，返回值为bool
    def press_mouse_button(self, button, seconds=1):
        """
        按住鼠标按键N秒再松开
        :param button: 鼠标按键，可以是'left'、'right'或'middle'
        :param seconds: 按住的时间，单位为秒
        :return: 操作成功返回True，失败返回False
        """
        # 参数校验
        if button not in ['left', 'right', 'middle']:
            self.logger.error("参数button必须是'left'、'right'或'middle'")
            return False
        if not isinstance(seconds, (int, float)) or seconds <= 0:
            self.logger.error("参数seconds必须是正数")
            return False

        try:
            # 按下鼠标按键
            pyautogui.mouseDown(button=button)
            # 等待指定时间
            time.sleep(seconds)
            # 松开鼠标按键
            pyautogui.mouseUp(button=button)
            self.logger.info(f"按住鼠标{button}键{seconds}秒后松开成功")
            return True
        except Exception as e:
            self.logger.error(f"按住鼠标{button}键{seconds}秒后松开失败，错误信息：{e}")
            return False

    # 按住N秒再松开，参数为键盘上的任何按键和时间，返回值为bool
    def press_key(self, key, seconds=1):
        """
        按住键盘按键N秒再松开
        :param key: 键盘按键，可以是任何有效的按键名称
        :param seconds: 按住的时间，单位为秒
        :return: 操作成功返回True，失败返回False
        """
        # 参数校验
        if not isinstance(seconds, (int, float)) or seconds <= 0:
            self.logger.error("参数seconds必须是正数")
            return False
        if not isinstance(key, str) or len(key) == 0:
            self.logger.error("参数key必须是有效的按键名称")
            return False

        try:
            # 按下键盘按键
            pyautogui.keyDown(key)
            # 等待指定时间
            time.sleep(seconds)
            # 松开键盘按键
            pyautogui.keyUp(key)
            self.logger.info(f"按住键盘{key}键{seconds}秒后松开成功")
            return True
        except Exception as e:
            self.logger.error(f"按住键盘{key}键{seconds}秒后松开失败，错误信息：{e}")
            return False

    # 文本粘贴，参数为text，返回值为bool
    def input_text(self, text):
        self.pyperclip.copy(text)
        self.pyautogui.hotkey('ctrl', 'v')
        self.logger.info(f"输入文本{text}成功")
        return True

    # 图片识别，参数为image_path，返回值为bool和location
    def image_recognition(self, image_path):
        if not os.path.exists(image_path):
            self.logger.error(f"图片文件不存在: {image_path}")
            return False, None
        try:
            location = self.pyautogui.locateCenterOnScreen(image_path)
            if location is not None:
                self.logger.info(f"找到图片: {image_path}，位置: {location}")
                return True, location
            else:
                self.logger.error(f"未找到图片: {image_path}")
                return False, None
        except self.pyautogui.ImageNotFoundException:
            self.logger.error(f"未找到图片: {image_path}")
            return False, None

    # 图片识别后点击，参数为image_path，返回值为bool
    def click_on_image(self, image_path):
        found, location = self.image_recognition(image_path)
        if found:
            self.click_at_position(location.x, location.y)
            self.logger.info(f"点击图片{image_path}成功")
            return True
        else:
            return False
    
    # 模拟组合按键，参数为key1,key2，返回值为bool
    def hotkey(self, key1, key2):
        self.pyautogui.hotkey(key1, key2)
        self.logger.info(f"按下组合键{key1}+{key2}成功")
        return True

    # 模拟单按键，参数为key，返回值为bool
    def press(self, key):
        try:
            self.pyautogui.press(key)
            self.logger.info(f"按下按键{key}成功")
            return True
        except Exception as e:
            self.logger.error(f"按下按键{key}失败: {str(e)}")
            return False

    # 鼠标滚动方法，参数为滚动量（正数向上，负数向下）
    def scroll(self, amount):
        try:
            self.pyautogui.scroll(amount)
            self.logger.info(f"鼠标滚动{amount}步成功")
            return True
        except Exception as e:
            self.logger.error(f"鼠标滚动失败: {str(e)}")
            return False

    # 鼠标拖拽方法，参数为起始坐标和结束坐标
    def drag(self, start_xy, end_xy, duration=0.5):
        try:
            if isinstance(start_xy, str):
                start_x, start_y = map(int, start_xy.split(','))
            elif isinstance(start_xy, tuple):
                start_x, start_y = start_xy
            if isinstance(end_xy, str):
                end_x, end_y = map(int, end_xy.split(','))
            elif isinstance(end_xy, tuple):
                end_x, end_y = end_xy
            self.pyautogui.moveTo(start_x, start_y, duration=0.2)
            self.pyautogui.dragTo(end_x, end_y, duration=duration)
            self.logger.info(f"从({start_x},{start_y})拖拽到({end_x},{end_y})成功")
            return True
        except Exception as e:
            self.logger.error(f"鼠标拖拽失败: {str(e)}")
            return False

    # 延时等待，参数为s，返回值为bool
    def sleep(self, s):
        self.time.sleep(s)
        self.logger.info(f"延时{s}秒成功")
        return True

    # 截图保存到本地，支持全屏或区域截图，参数为保存路径和可选的区域参数，返回值为bool
    def capture_screen(self, output_path, region=None):
        """
        截取屏幕并保存为文件
        
        Args:
            output_path: 截图保存路径
            region: 可选参数，截图区域，格式为 (left, top, width, height)
            
        Returns:
            bool: 操作是否成功
        """
        try:
            if region:
                # 区域截图
                if not isinstance(region, (tuple, list)) or len(region) != 4:
                    self.logger.error(f"无效的区域参数: {region}，应为 (left, top, width, height)")
                    return False
                    
                screenshot = pyautogui.screenshot(region=region)
                self.logger.info(f"区域截图成功，区域: {region}")
            else:
                # 全屏截图
                screenshot = pyautogui.screenshot()
                self.logger.info("全屏截图成功")
                
            # 保存截图
            output_dir = os.path.dirname(output_path)
            if not os.path.exists(output_dir) and output_dir:
                os.makedirs(output_dir)
                
            screenshot.save(output_path)
            self.logger.info(f"截图已保存至: {output_path}")
            return True
            
        except Exception as e:
            self.logger.error(f"截图失败: {str(e)}")
            return False


    # 获取当前鼠标位置（需按F8触发）    
    def get_mouse_position(self):
            try:
                self.logger.info("请按下F8键获取当前鼠标位置...")
                with self.keyboard.Listener(on_press=lambda key: key == self.keyboard.Key.f8) as listener:
                    listener.join()
                x, y = self.pyautogui.position()
                self.logger.info(f"获取鼠标位置成功: ({x}, {y})")
                return (x, y)
            except Exception as e:
                self.logger.error(f"获取鼠标位置失败: {str(e)}")
                return (0, 0)

    # 日志记录，参数为需要记录的内容，返回值为bool
    def log(self, content):
        self.logger.info(content)
        return True

if __name__ == '__main__':
    tool = AutomationTool()
    # 创建自动化工具实例